#include "my_wifi.h"

static const char *TAG = "MY_wifi.c";
static int s_retry_num = 0;

static my_wifi_t private_wifi_info = {};

static void event_handler(void* arg, esp_event_base_t event_base,
								int32_t event_id, void* event_data)
{
	if (event_base == WIFI_EVENT) {
		if (event_id == WIFI_EVENT_STA_START) {
			tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, MY_HOST_NAME);
			esp_wifi_connect();
		}
		else if (event_id == WIFI_EVENT_STA_DISCONNECTED) {
			if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
				esp_wifi_connect();
				s_retry_num++;
				ESP_LOGW(TAG, "retry to connect to the AP");
			}
			else {
				if (private_wifi_info.disconnect_cb) {
					private_wifi_info.disconnect_cb();
				}
			}
		}
		else if (event_id == WIFI_EVENT_AP_STACONNECTED) {
			wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
			ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
					MAC2STR(event->mac), event->aid);
			if (private_wifi_info.ap_staconnect_cb) {
				private_wifi_info.ap_staconnect_cb();
			}
		}
		else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
			wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
			ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
					MAC2STR(event->mac), event->aid);
			if (private_wifi_info.ap_stadisconnect_cb) {
				private_wifi_info.ap_stadisconnect_cb();
			}
		}
	}
	else if (event_base == IP_EVENT) {
		if (event_id == IP_EVENT_STA_GOT_IP) {
			ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
			ESP_LOGI(TAG, "got ip:%s", ip4addr_ntoa(&event->ip_info.ip));
			s_retry_num = 0;

			if (private_wifi_info.connect_cb) {
				private_wifi_info.connect_cb(ip4addr_ntoa(&event->ip_info.ip));
			}
		}
	}
}

int wifi_init_sta(my_wifi_t *info)
{
	int ret = 0;

	tcpip_adapter_init();

	ESP_ERROR_CHECK(esp_event_loop_create_default());

	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_wifi_init(&cfg));

	ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
	ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));

	wifi_config_t wifi_config = {};
	
	memcpy(wifi_config.sta.ssid, info->ssid, strlen((char *)info->ssid));
	memcpy(wifi_config.sta.password, info->password, strlen((char *)info->password));

	if (strlen((char *)wifi_config.sta.password)) {
		wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
	}
	wifi_config.sta.listen_interval = 10;
	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
	ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
	ESP_ERROR_CHECK(esp_wifi_start() );

	ESP_LOGI(TAG, "wifi_init_sta finished.");

	return ret;
}

void wifi_init_softap(my_wifi_t *info)
{
	tcpip_adapter_init();
	ESP_ERROR_CHECK(esp_event_loop_create_default());

	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_wifi_init(&cfg));

	ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));

	wifi_config_t wifi_config = {0};

	memcpy(wifi_config.ap.ssid, info->ssid, strlen((char *)info->ssid));
	wifi_config.ap.ssid_len = strlen((char *)info->ssid);
	memcpy(wifi_config.ap.password, info->password, strlen((char *)info->password));
	wifi_config.ap.max_connection = info->max_connection;
	wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;

	if (strlen((char *)wifi_config.ap.password) == 0) {
		wifi_config.ap.authmode = WIFI_AUTH_OPEN;
	}

	if (wifi_config.ap.max_connection == 0) {
		wifi_config.ap.max_connection = 1;
	}

	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
	ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
	ESP_ERROR_CHECK(esp_wifi_start());

	ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s",
			 wifi_config.ap.ssid, wifi_config.ap.password);
}

void my_wifi_init(my_wifi_t *info, wifi_mode_t mode)
{
	memmove(&private_wifi_info, info, sizeof(my_wifi_t));

	if (mode == WIFI_MODE_STA) {
		if (strlen((char *)info->ssid) == 0 || strlen((char *)info->password) == 0) {
			ESP_LOGE(TAG, "ssid or password is NULL");
			return ;
		}
		ESP_LOGW(TAG, "ESP_WIFI_MODE_STA");
		wifi_init_sta(info);
	} else if (mode == WIFI_MODE_AP) {
		if (strlen((char *)info->ssid) == 0 ) {
			ESP_LOGE(TAG, "ssid is NULL");
			return ;
		}
		ESP_LOGW(TAG, "ESP_WIFI_MODE_AP");
		wifi_init_softap(info);
	}
}
